/*
 * Código de identificación fiscal ( CIF ) is the tax identification code for Spanish legal entities
 * Further rules can be found in Spanish on http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal
 *
 * Spanish CIF structure:
 *
 * [ T ][ P ][ P ][ N ][ N ][ N ][ N ][ N ][ C ]
 *
 * Where:
 *
 * T: 1 character. Kind of Organization Letter: [ABCDEFGHJKLMNPQRSUVW]
 * P: 2 characters. Province.
 * N: 5 characters. Secuencial Number within the province.
 * C: 1 character. Control Digit: [0-9A-J].
 *
 * [ T ]: Kind of Organizations. Possible values:
 *
 *   A. Corporations
 *   B. LLCs
 *   C. General partnerships
 *   D. Companies limited partnerships
 *   E. Communities of goods
 *   F. Cooperative Societies
 *   G. Associations
 *   H. Communities of homeowners in horizontal property regime
 *   J. Civil Societies
 *   K. Old format
 *   L. Old format
 *   M. Old format
 *   N. Nonresident entities
 *   P. Local authorities
 *   Q. Autonomous bodies, state or not, and the like, and congregations and religious institutions
 *   R. Congregations and religious institutions (since 2008 ORDER EHA/451/2008)
 *   S. Organs of State Administration and regions
 *   V. Agrarian Transformation
 *   W. Permanent establishments of non-resident in Spain
 *
 * [ C ]: Control Digit. It can be a number or a letter depending on T value:
 * [ T ]  -->  [ C ]
 * ------    ----------
 *   A         Number
 *   B         Number
 *   E         Number
 *   H         Number
 *   K         Letter
 *   P         Letter
 *   Q         Letter
 *   S         Letter
 *
 */
$.validator.addMethod("cifES", function (value, element) {
    "use strict";

    if (this.optional(element)) {
        return true;
    }

    var cifRegEx = new RegExp(/^([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])$/gi);
    var letter = value.substring(0, 1), // [ T ]
        number = value.substring(1, 8), // [ P ][ P ][ N ][ N ][ N ][ N ][ N ]
        control = value.substring(8, 9), // [ C ]
        all_sum = 0,
        even_sum = 0,
        odd_sum = 0,
        i, n,
        control_digit,
        control_letter;

    function isOdd(n) {
        return n % 2 === 0;
    }

    // Quick format test
    if (value.length !== 9 || !cifRegEx.test(value)) {
        return false;
    }

    for (i = 0; i < number.length; i++) {
        n = parseInt(number[i], 10);

        // Odd positions
        if (isOdd(i)) {

            // Odd positions are multiplied first.
            n *= 2;

            // If the multiplication is bigger than 10 we need to adjust
            odd_sum += n < 10 ? n : n - 9;

            // Even positions
            // Just sum them
        } else {
            even_sum += n;
        }
    }

    all_sum = even_sum + odd_sum;
    control_digit = ( 10 - ( all_sum ).toString().substr(-1) ).toString();
    control_digit = parseInt(control_digit, 10) > 9 ? "0" : control_digit;
    control_letter = "JABCDEFGHI".substr(control_digit, 1).toString();

    // Control must be a digit
    if (letter.match(/[ABEH]/)) {
        return control === control_digit;

        // Control must be a letter
    } else if (letter.match(/[KPQS]/)) {
        return control === control_letter;
    }

    // Can be either
    return control === control_digit || control === control_letter;

}, "Please specify a valid CIF number.");
